package com.bytz.modules.system.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.bytz.common.api.vo.Result;
import com.bytz.common.constant.CommonConstant;
import com.bytz.common.constant.SystemConfigKey;
import com.bytz.common.system.api.ISysBaseApi;
import com.bytz.common.system.api.ISysConfigApi;
import com.bytz.common.util.CommonSecurityUtils;
import com.bytz.common.util.MD5Util;
import com.bytz.common.util.RedisUtil;
import com.bytz.common.util.oConvertUtils;
import com.bytz.modules.system.model.LoginResellerOut;
import com.bytz.modules.system.model.SecuritySettings;
import com.bytz.modules.system.model.SysLoginModel;
import com.bytz.modules.system.security.vo.LoginReseller;
import com.bytz.modules.system.service.ISysLogService;
import com.bytz.modules.system.service.impl.SysTokenService;
import com.bytz.modules.system.util.RandImageUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * @Author scott
 * @since 2018-12-17
 */
@RestController
@RequestMapping("/sys")
@Api(tags = "用户登录")
@Slf4j
public class LoginController {

    @Autowired
    private SysTokenService tokenService;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private ISysBaseApi sysBaseApi;
    @Autowired
    private ISysLogService logService;
    @Autowired
    private RedisUtil redisUtil;

    private static final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";

    @Autowired
    private SecuritySettings securitySettings;

    @Value("${bytz.check-captcha:true}")
    private Boolean checkCapcha;

    @Value("${bytz.capcha-expr-time:60}")
    private Integer randomImageExprTime;

    @Autowired
    private ISysConfigApi sysConfigApi;

    @ApiOperation("登录接口")
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel) throws Exception {
        Result<JSONObject> result = new Result<JSONObject>();
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();
        username = CommonSecurityUtils.decryptRSA(securitySettings.getPrivateKey(), username);
        password = CommonSecurityUtils.decryptRSA(securitySettings.getPrivateKey(), password);

        if (BooleanUtil.isTrue(checkCapcha)) {
            String captcha = sysLoginModel.getCaptcha();
            if (captcha == null) {
                result.error500("验证码无效");
                return result;
            }
            String lowerCaseCaptcha = captcha.toLowerCase();
            String realKey = MD5Util.MD5Encode(lowerCaseCaptcha + sysLoginModel.getCheckKey(), "utf-8");
            Object checkCode = redisUtil.get(realKey);
            // 当进入登录页时，有一定几率出现验证码错误 #1714
            if (checkCode == null || !StrUtil.equals(checkCode.toString(), lowerCaseCaptcha)) {
                result.error500("验证码错误");
                return result;
            }
        }

        // 用户验证
        Authentication authentication = null;

        try {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                sysBaseApi.addLog("用户名: " + username + ",密码错误登录失败！", CommonConstant.LOG_TYPE_1, null);
            }

            result.error500("用户名或密码错误");
            return result;
        }

        //用户登录信息
        LoginReseller loginReseller = (LoginReseller) authentication.getPrincipal();
        recordLoginInfo(loginReseller, result);

        sysBaseApi.addLog("经销商: " + username + ",登录成功！", CommonConstant.LOG_TYPE_1, null);
        return result;
    }

    /**
     * 获取访问量
     *
     * @return
     */
    @GetMapping("loginfo")
    public Result<JSONObject> loginfo() {
        Result<JSONObject> result = new Result<JSONObject>();
        JSONObject obj = new JSONObject();
        //update-begin--Author:zhangweijian  Date:20190428 for：传入开始时间，结束时间参数
        // 获取一天的开始和结束时间
        Calendar calendar = new GregorianCalendar();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date dayStart = calendar.getTime();
        calendar.add(Calendar.DATE, 1);
        Date dayEnd = calendar.getTime();
        // 获取系统访问记录
        Long totalVisitCount = logService.findTotalVisitCount();
        obj.put("totalVisitCount", totalVisitCount);
        Long todayVisitCount = logService.findTodayVisitCount(dayStart, dayEnd);
        obj.put("todayVisitCount", todayVisitCount);
        Long todayIp = logService.findTodayIp(dayStart, dayEnd);
        //update-end--Author:zhangweijian  Date:20190428 for：传入开始时间，结束时间参数
        obj.put("todayIp", todayIp);
        result.setResult(obj);
        result.success("登录成功");
        return result;
    }

    /**
     * 获取访问量
     *
     * @return
     */
    @GetMapping("visitInfo")
    public Result<List<Map<String, Object>>> visitInfo() {
        Result<List<Map<String, Object>>> result = new Result<List<Map<String, Object>>>();
        Calendar calendar = new GregorianCalendar();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date dayEnd = calendar.getTime();
        calendar.add(Calendar.DAY_OF_MONTH, -7);
        Date dayStart = calendar.getTime();
        List<Map<String, Object>> list = logService.findVisitCount(dayStart, dayEnd);
        result.setResult(oConvertUtils.toLowerCasePageList(list));
        return result;
    }


    /**
     * 用户信息
     *
     * @param reseller
     * @param result
     * @return
     */
    protected void recordLoginInfo(LoginReseller reseller, Result<JSONObject> result) {
        // 获取用户部门信息
        JSONObject obj = new JSONObject();
        obj.put("multi_depart", 1);
        obj.put("token", tokenService.createToken(reseller));
        obj.put("userInfo", BeanUtil.toBean(reseller, LoginResellerOut.class));
        result.setResult(obj);
        result.success("登录成功");
    }

    /**
     * 后台生成图形验证码 ：有效
     *
     * @param response
     * @param key
     */
    @ApiOperation("获取验证码")
    @GetMapping(value = "/randomImage/{key}")
    public Result<String> randomImage(HttpServletResponse response, @PathVariable String key) {
        Result<String> res = new Result<String>();
        try {
            String code = RandomUtil.randomString(BASE_CHECK_CODES, 4);
            String lowerCaseCode = code.toLowerCase();
            String realKey = MD5Util.MD5Encode(lowerCaseCode + key, "utf-8");
            redisUtil.set(realKey, lowerCaseCode, randomImageExprTime);
            String base64 = RandImageUtil.generate(code);
            res.setSuccess(true);
            res.setResult(base64);
        } catch (Exception e) {
            res.error500("获取验证码出错" + e.getMessage());
            e.printStackTrace();
        }
        return res;
    }

    /**
     * 图形验证码
     *
     * @param sysLoginModel
     * @return
     */
    @RequestMapping(value = "/checkCaptcha", method = RequestMethod.POST)
    public Result<?> checkCaptcha(@RequestBody SysLoginModel sysLoginModel) {
        String captcha = sysLoginModel.getCaptcha();
        String checkKey = sysLoginModel.getCheckKey();
        if (captcha == null) {
            return Result.error("验证码无效");
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        String realKey = MD5Util.MD5Encode(lowerCaseCaptcha + checkKey, "utf-8");
        Object checkCode = redisUtil.get(realKey);
        if (checkCode == null || !checkCode.equals(lowerCaseCaptcha)) {
            return Result.error("验证码错误");
        }
        return Result.ok();
    }

}